﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Net;
using System.IO;
using System.Diagnostics;
using System.Threading;

namespace SkypeTranslator.Utilities
{
	internal interface IPerformanceCounter
	{
		long Count
		{
			get;
		}
		long Frequency
		{
			get;
		}
	}

	internal class Win32PerformanceCounter : IPerformanceCounter
	{
		public long Count
		{
			get
			{
				long result = 0L;
				NativeMethods.QueryPerformanceCounter(ref result);
				return result;
			}
		}
		public long Frequency
		{
			get
			{
				long result = 0L;
				NativeMethods.QueryPerformanceFrequency(ref result);
				return result;
			}
		}
	}

	internal class DefaultPerformanceCounter : IPerformanceCounter
	{
		public long Count
		{
			get
			{
				return DateTime.UtcNow.Ticks;
			}
		}
		public long Frequency
		{
			get
			{
				return 10000000L;
			}
		}
	}

	public static class NativeMethods
	{
		[System.Runtime.InteropServices.DllImport("KERNEL32.DLL", SetLastError = true)]
		internal static extern bool QueryPerformanceCounter(ref long lpPerformanceCount);
		[System.Runtime.InteropServices.DllImport("KERNEL32.DLL", SetLastError = true)]
		internal static extern bool QueryPerformanceFrequency(ref long lpFrequency);
	}

	public class CodeClock
	{
		private long elapsedCount;
		private long startCount;
		private IPerformanceCounter _clock;
		public float Seconds
		{
			get
			{
				return (float)this.elapsedCount / (float)this._clock.Frequency;
			}
		}
		public CodeClock()
		{
			if (IsWin32Platform)
			{
				this._clock = new Win32PerformanceCounter();
				return;
			}
			this._clock = new DefaultPerformanceCounter();
		}
		public void Start()
		{
			this.startCount = this._clock.Count;
		}
		public void Stop()
		{
			long count = this._clock.Count;
			this.elapsedCount += count - this.startCount;
		}
		public void Clear()
		{
			this.elapsedCount = 0L;
		}

		public static bool IsWin32Platform
		{
			get
			{
				PlatformID platform = Environment.OSVersion.Platform;
				return platform == PlatformID.Win32NT || platform == PlatformID.Win32Windows || platform == PlatformID.Win32S || platform == PlatformID.WinCE;
			}
		}

		public override string ToString()
		{
			return this.Seconds.ToString();
		}
	}


	public class FileTransferRequest
	{
		public Uri RemoteFile
		{
			get;
			private set;
		}
		public string LocalFile
		{
			get;
			private set;
		}
		public FileTransferRequest(Uri remoteFile, string localFile)
		{
			this.RemoteFile = remoteFile;
			this.LocalFile = localFile;
		}
	}

	public interface IRemoteFileTransfer
	{
		void Upload(FileTransferRequest request);
		void Download(FileTransferRequest request);
	}

	public class HttpFileTransfer : IRemoteFileTransfer
	{
		private readonly string _userId;
		private readonly string _password;
		public HttpFileTransfer()
		{
		}
		public HttpFileTransfer(string userId, string password)
		{
			this._userId = userId;
			this._password = password;
		}
		public void Upload(FileTransferRequest request)
		{
			try
			{
				using (WebClient webClient = new WebClient())
				{
					if (!string.IsNullOrEmpty(this._userId) && !string.IsNullOrEmpty(this._password))
					{
						webClient.Credentials = new NetworkCredential(this._userId, this._password);
					}
					webClient.UploadFile(request.RemoteFile, request.LocalFile);
				}
			}
			catch (System.Net.WebException innerException)
			{
				throw;
			}
		}
		public void Download(FileTransferRequest request)
		{
			try
			{
				using (WebClient webClient = new WebClient())
				{
					if (!string.IsNullOrEmpty(this._userId) && !string.IsNullOrEmpty(this._password))
					{
						webClient.Credentials = new NetworkCredential(this._userId, this._password);
					}
					string directoryName = Path.GetDirectoryName(request.LocalFile);
					if (!Directory.Exists(directoryName))
					{
						Directory.CreateDirectory(directoryName);
					}
					webClient.DownloadFile(request.RemoteFile, request.LocalFile);
				}
			}
			catch (System.Net.WebException)
			{
				throw;
			}
			catch (System.NotSupportedException)
			{
				throw;
			}
			catch (System.IO.IOException)
			{
				throw;
			}
		}
	}


	public class StringDiff
	{
		private string _alignedLeft;
		private string _alignedRight;
		private string _diffMask;
		public string AlignedLeft
		{
			get
			{
				return this._alignedLeft;
			}
		}
		public string AlignedRight
		{
			get
			{
				return this._alignedRight;
			}
		}
		public string DiffMask
		{
			get
			{
				return this._diffMask;
			}
		}
		public static StringDiff Compute(string left, string right, bool ignoreCase)
		{
			if (left == right)
			{
				return new StringDiff(left, right, new string('|', left.Length));
			}
			string[] array = StringDiff.ComputeDiff(left, right, ignoreCase);
			return new StringDiff(array[0], array[2], array[1]);
		}
		private StringDiff(string alignedLeft, string alignedRight, string diffMask)
		{
			this._alignedLeft = alignedLeft;
			this._alignedRight = alignedRight;
			this._diffMask = diffMask;
		}
		private static string[] ComputeDiff(string s1, string s2, bool ignoreCase)
		{
			int[,] array = new int[s1.Length + 1, s2.Length + 1];
			array[0, 0] = 0;
			for (int i = 1; i <= s2.Length; i++)
			{
				array[0, i] = array[0, i - 1] + 1;
			}
			for (int j = 1; j <= s1.Length; j++)
			{
				array[j, 0] = array[j - 1, 0] + 1;
				for (int k = 1; k <= s2.Length; k++)
				{
					int num = array[j - 1, k - 1];
					if (!StringDiff.CompareEqual(s1[j - 1], s2[k - 1], ignoreCase))
					{
						num++;
					}
					array[j, k] = Math.Min(num, Math.Min(array[j - 1, k] + 1, array[j, k - 1] + 1));
				}
			}
			return StringDiff.traceBack("", "", "", array, s1.Length, s2.Length, s1, s2, ignoreCase);
		}
		private static string[] traceBack(string row1, string row2, string row3, int[,] m, int i, int j, string s1, string s2, bool ignoreCase)
		{
			if (i > 0 && j > 0)
			{
				int num = m[i - 1, j - 1];
				char c = '|';
				if (!StringDiff.CompareEqual(s1[i - 1], s2[j - 1], ignoreCase))
				{
					num++;
					c = ' ';
				}
				if (m[i, j] == num)
				{
					return StringDiff.traceBack(s1[i - 1] + row1, c + row2, s2[j - 1] + row3, m, i - 1, j - 1, s1, s2, ignoreCase);
				}
				if (m[i, j] == m[i - 1, j] + 1)
				{
					return StringDiff.traceBack(s1[i - 1] + row1, ' ' + row2, '-' + row3, m, i - 1, j, s1, s2, ignoreCase);
				}
				return StringDiff.traceBack('-' + row1, ' ' + row2, s2[j - 1] + row3, m, i, j - 1, s1, s2, ignoreCase);
			}
			else
			{
				if (i > 0)
				{
					return StringDiff.traceBack(s1[i - 1] + row1, ' ' + row2, '-' + row3, m, i - 1, j, s1, s2, ignoreCase);
				}
				if (j > 0)
				{
					return StringDiff.traceBack('-' + row1, ' ' + row2, s2[j - 1] + row3, m, i, j - 1, s1, s2, ignoreCase);
				}
				return new string[]
				{
					row1, 
					row2, 
					row3
				};
			}
		}
		private static bool CompareEqual(char c1, char c2, bool ignoreCase)
		{
			return c1 == c2 || (ignoreCase && char.ToLower(c1) == char.ToLower(c2));
		}
	}


	public enum SizeUnits
	{
		Bytes,
		Kilobytes,
		Megabytes,
		Gigabytes
	}

}
